/*
 * ml20gui - The MSN Webcam Recorder
 * This source code is under the GNU Public License (GPL).
 * Written by Ramiro Polla
 * Initial release: june 3rd, 2005
 *
 * this program records MSN Webcam Video
 */

#include "ml20gui.h"
#include <remote-ext.h>

static void add_lvitem( HWND hwnd, int ID, long lparam );

extern HINSTANCE hInst;
extern HWND hdialog;
extern HWND hinf;
extern device_t *decive;
extern int ID_TIMER;
extern char error[PCAP_ERRBUF_SIZE];
extern int nochecksum;

static const int INT_TIME = 1000;

extern char *expression;

static int which_cap_image( int flags )
{
    if( IS_SET( flags, NO_CAP ) )
        return 1;
    else if( !IS_SET( flags, DO_CAP ) )
        return 1;
    else if( IS_SET( flags, PROMISCUOUS_CAP ) )
        return 2;
    else
        return 0;
}

LRESULT CALLBACK IntProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    NMLVDISPINFO *dp;

    switch(msg) {
        case WM_INITDIALOG:
        {
            device_t *tdev;

            HIMAGELIST hSmall;
            HICON hiconItem;

            hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK, 1, 1);

            hiconItem = LoadIcon( hInst, MAKEINTRESOURCE(IDI_GREEN));
            ImageList_AddIcon(hSmall, hiconItem);
            DestroyIcon(hiconItem);
            hiconItem = LoadIcon( hInst, MAKEINTRESOURCE(IDI_RED));
            ImageList_AddIcon(hSmall, hiconItem);
            DestroyIcon(hiconItem);
            hiconItem = LoadIcon( hInst, MAKEINTRESOURCE(IDI_BLUE));
            ImageList_AddIcon(hSmall, hiconItem);
            DestroyIcon(hiconItem);

            SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETIMAGELIST, LVSIL_SMALL, (long) hSmall );
            SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT );
            SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_GRIDLINES, LVS_EX_GRIDLINES );

            SetWindowText( hwnd, str_interfaces );
            SetDlgItemText( hwnd, IDC_SS, str_start_stop );
            SetDlgItemText( hwnd, IDC_ADD_FILE, str_add_file );

            add_lvcolumn( hwnd, IDC_DLIST, 0, str_name, 340, LVCFMT_LEFT | LVCFMT_COL_HAS_IMAGES | LVCFMT_IMAGE );
            add_lvcolumn( hwnd, IDC_DLIST, 1, str_kb, 60, LVCFMT_LEFT );

            if( !reg_read_dword( "NoChecksum", (uint32_t*) &nochecksum ) )
                nochecksum = 0;
            SendDlgItemMessage( hwnd, IDC_NOCHECKSUM, BM_SETCHECK,
                                nochecksum ? BST_CHECKED : BST_UNCHECKED, 0 );

            for( tdev = decive ; tdev->next != 0 ; tdev = tdev->next )
                add_lvitem( hwnd, IDC_DLIST, (long) tdev );

            SetTimer( hwnd, ID_TIMER++, INT_TIME, NULL );
        }
            break;
        case WM_TIMER:
        {
            int i;
            LVITEM two;
            LVITEM three;
            device_t *tdev;
            int p = SendDlgItemMessage( hwnd, IDC_DLIST, LVM_GETITEMCOUNT, 0, 0 );

            memset( &two, 0, sizeof(LVITEM) );
            memset( &three, 0, sizeof(LVITEM) );
            two.pszText = LPSTR_TEXTCALLBACK;
            three.mask = LVIF_PARAM;

            for( i = 0 ; i < p ; i++ ) {
                three.iItem = i;
                SendDlgItemMessage( hwnd, IDC_DLIST, LVM_GETITEM, 0, (LPARAM) &three );
                tdev = ((device_t *) three.lParam);

                two.iItem = i;

                two.mask = LVIF_TEXT;
                two.iSubItem = 1;
                SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETITEM, 1, (long) &two );

                two.iImage = which_cap_image( tdev->flags );
                two.mask = LVIF_IMAGE;
                two.iSubItem = 0;
                SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETITEM, 1, (long) &two );
            }
        }
            break;
        case WM_CLOSE:
        {
            DestroyWindow( hwnd );
            hinf = 0;
        }
        break;
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
            case IDC_SS:
                {
                    int index = GetDlgListSelection( hwnd, IDC_DLIST );
                    if( index != -1 ) {
                        int lRes;
                        LVITEM two;
                        device_t *tdev;

                        tdev = (device_t *) GetDlgListItem( hwnd, IDC_DLIST, index );

                        if( IS_SET( tdev->flags, DO_CAP ) )
                            lRes = MessageBox( hwnd, str_stop_listening, str_stop_listening, MB_YESNO );
                        else
                            lRes = MessageBox( hwnd, str_start_listening, str_start_listening, MB_YESNO );

                        if( lRes == IDYES ) {
                            if( !IS_SET( tdev->flags, DO_CAP ) )
                                SET_BIT( tdev->flags, DO_CAP );
                            else
                                UNSET_BIT( tdev->flags, DO_CAP );
                        }

                        memset( &two, 0, sizeof(LVITEM) );
                        two.iItem = index;
                        two.iSubItem = 0;
                        two.mask = LVIF_IMAGE;
                        two.iImage = which_cap_image( tdev->flags );

                        SendDlgItemMessage( hwnd, IDC_DLIST, LVM_SETITEM, 1, (long) &two );
                    }
                }
                break;
            case ID_PROMISCUOUS:
                {
                    int index = GetDlgListSelection( hwnd, IDC_DLIST );
                    if( index != -1 ) {
                        device_t *tdev;

                        tdev = (device_t *) GetDlgListItem( hwnd, IDC_DLIST, index );

                        if( !IS_SET( tdev->flags, OFFLINE_CAP ) ) {
                            int promisc;
                            SET_BIT( tdev->flags, NO_CAP );
                            UNSET_BIT( tdev->flags, DO_CAP );
                            Sleep( 1 );

                            if( IS_SET( tdev->flags, PROMISCUOUS_CAP ) ) {
                                promisc = 0;
                                UNSET_BIT( tdev->flags, PROMISCUOUS_CAP );
                            } else {
                                promisc = 1;
                                SET_BIT( tdev->flags, PROMISCUOUS_CAP );
                            }

                            pcap_close( tdev->pd );

                            if( (tdev->pd = pcap_open_live( tdev->name, SNAPLEN, promisc, 10, error )) != NULL ) {
                                tdev->hdrsz = find_hdrsize( tdev->pd );
                                if( pcap_compile(tdev->pd, &tdev->fcode, expression, 1, 0) >= 0 )
                                    if( pcap_setfilter(tdev->pd, &decive->fcode) >= 0 ) {
                                        SET_BIT( tdev->flags, DO_CAP );
                                    }
                            }
                            UNSET_BIT( tdev->flags, NO_CAP );
                        }
                    }
                }
                break;
            case IDC_NOCHECKSUM:
                nochecksum = GetDlgButtonCheck( hwnd, IDC_NOCHECKSUM );
                reg_write_dword( "NoChecksum", nochecksum );
                break;
            case IDC_ADD_FILE:
                {
                    char *fname;
                    device_t *tdev;

                    if( (fname = OpenFileDlg( hwnd, "libpcap file\0*\0", "" )) ) {
                        for( tdev = decive; tdev->next != 0; tdev=tdev->next );

                        tdev->name = calloc( 1, strlen(fname) + 1 + 7 );
                        sprintf( tdev->name, "file://%s", fname );
                        tdev->description = calloc( 1, strlen(fname)+1 );
                        strcpy( tdev->description, fname );

                        if( (tdev->pd = pcap_open_offline( fname, error )) != NULL ) {
                            tdev->hdrsz = find_hdrsize( tdev->pd );
                            if( pcap_compile(tdev->pd, &tdev->fcode, expression, 1, 0) >= 0 )
                                if( pcap_setfilter(tdev->pd, &decive->fcode) >= 0 ) {
                                    SET_BIT( tdev->flags, OFFLINE_CAP );
                                    SET_BIT( tdev->flags, DO_CAP );
                                    add_lvitem( hwnd, IDC_DLIST, (long) tdev );
                                }
                        }

                        tdev->next = calloc(1, sizeof(device_t) );
                    }
                }
                break;
            }
            break;
        case WM_NOTIFY:
        {
            device_t *tdev;
            char kbbuf[32];

            switch (((LPNMHDR) lParam)->code) {
            case LVN_GETDISPINFO:
                dp = ((NMLVDISPINFO *)lParam);
                tdev = (device_t *) (dp->item.lParam);

                if( tdev ) {
                    switch (dp->item.iSubItem) {
                    case 0:
                        dp->item.pszText = tdev->description;
                        break;
                    case 1:
                        sprintf( kbbuf, "%d", tdev->bytes / 1024 );
                        dp->item.pszText = kbbuf;
                        break;
                    }
                }
                break;
                case NM_RCLICK:
                {
                    HMENU hSub = CreatePopupMenu( );
                    POINT CurPos;

                    AppendMenu( hSub, MF_ENABLED | MF_STRING, IDC_ADD_FILE, str_add_file );
                    AppendMenu( hSub, MF_ENABLED | MF_STRING, IDC_SS, str_start_stop );
                    AppendMenu( hSub, MF_ENABLED | MF_STRING, ID_PROMISCUOUS, "Promiscuous" );

                    GetCursorPos( &CurPos );
                    SetForegroundWindow( hwnd );
                    TrackPopupMenu( hSub, TPM_RIGHTALIGN | TPM_LEFTBUTTON, CurPos.x, CurPos.y, 0, hwnd, 0 );
                    PostMessage(hwnd, WM_NULL, 0, 0);

                    DestroyMenu(hSub);
                }
                break;
            }
        }
        default:
            return FALSE;
    }
    return TRUE;
}

//equivalent to lipcap 8.1's init_linktype off_nl
int find_hdrsize( pcap_t *pd )
{
    switch ( pcap_datalink(pd) ) {
    case DLT_PRISM_HEADER:
        return 176;

    case DLT_IEEE802_11_RADIO:
        return 96;

    case DLT_IEEE802_11:
        return 32;

    case DLT_PFLOG:
        return 28;

    case DLT_IP_OVER_FC:
    case DLT_SLIP_BSDOS:
    case DLT_PPP_BSDOS:
        return 24;

    case DLT_IEEE802:
        return 22;

    case DLT_FDDI:
        return 21;

    case DLT_LINUX_SLL:
    case DLT_SLIP:
        return 16;

    case DLT_EN10MB:
    case DLT_EN3MB:
        return 14;

    //case DLT_ENC:
        //return 12;

    case DLT_ARCNET_LINUX:
    case DLT_ATM_RFC1483:
    case DLT_ATM_CLIP:
    case DLT_PPP_ETHER:
        return 8;

    case DLT_ARCNET:
        return 6;

    case DLT_NULL:
    case DLT_LOOP:
    case DLT_PPP:
    case DLT_C_HDLC:
    case DLT_PPP_SERIAL:
        return 4;

    case DLT_LTALK:
    case DLT_RAW:
    case DLT_FRELAY:
    default:
        return 0;
    }
    /* NOTREACHED */
}

static void add_lvitem( HWND hwnd, int ID, long lparam )
{
    LVITEM two;
    device_t *tdev = (device_t *) lparam;

    //ADD FILES TO THE LISTVIEW
    two.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE | LVIF_STATE;
    two.state = 0;
    two.stateMask = 0;

    two.iItem = 0;
    two.iImage = which_cap_image( tdev->flags );
    two.iSubItem = 0;
    two.lParam = (LPARAM) lparam;
    two.pszText = LPSTR_TEXTCALLBACK;
    SendDlgItemMessage( hwnd, ID, LVM_INSERTITEM, 0, (long) &two );
}
